package com.tang.lts.core.nio.processor;

import com.tang.lts.core.nio.channel.ChannelInitializer;
import com.tang.lts.core.nio.channel.NioChannel;
import com.tang.lts.core.nio.channel.NioChannelImpl;
import com.tang.lts.core.nio.config.NioServerConfig;
import com.tang.lts.core.nio.handler.Futures;
import com.tang.lts.core.nio.handler.NioHandler;
import com.tang.lts.core.nio.idle.IdleDetector;
import com.tang.lts.core.nio.loop.NioSelectorLoop;

import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
 * @author Tang
 * @classname NioServerProcessor
 * @description [  ]
 * @date 2022/5/12 23:43
 */
public class NioServerProcessor extends AbstractNioProcessor {

    private NioServerConfig serverConfig;

    private ServerSocketChannel serverSocketChannel;


    public NioServerProcessor(NioServerConfig serverConfig, NioHandler nioHandler,
                              ChannelInitializer channelInitializer) {
        super(nioHandler, channelInitializer);
        this.serverConfig = serverConfig;
        this.serverSocketChannel = newSocket();
    }

    private ServerSocketChannel newSocket() {
        ServerSocketChannel serverSocketChannel = null;
        try {
            serverSocketChannel = ServerSocketChannel.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return serverSocketChannel;
    }

    public ServerSocketChannel javaChannel() {
        return this.serverSocketChannel;
    }

    public NioSelectorLoop acceptSelectorLoop() {
        return this.selectorLoop;
    }

    public void register() throws ClosedChannelException {
        javaChannel().register(acceptSelectorLoop().selector(), SelectionKey.OP_ACCEPT);
    }

    @Override
    public NioChannel doAccept(NioSelectorLoop selectorLoop) {
        SocketChannel socketChannel = null;
        NioChannel nioChannel = null;
        try {
            socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            if (serverConfig.getTcpNoDelay() != null) {
                socketChannel.socket().setTcpNoDelay(serverConfig.getTcpNoDelay());
            }
            if (serverConfig.getReceiveBufferSize() != null) {
                socketChannel.socket().setReceiveBufferSize(serverConfig.getReceiveBufferSize());
            }
            if (serverConfig.getKeepAlive() != null) {
                socketChannel.socket().setKeepAlive(serverConfig.getKeepAlive());
            }
            if (serverConfig.getReuseAddress() != null) {
                socketChannel.socket().setReuseAddress(serverConfig.getReuseAddress());
            }
            if (serverConfig.getIpTos() != null) {
                socketChannel.socket().setTrafficClass(serverConfig.getIpTos());
            }
            if (serverConfig.getSoLinger() != null) {
                socketChannel.socket().setSoLinger(true, serverConfig.getSoLinger());
            }
            nioChannel = new NioChannelImpl(selectorLoop, this, socketChannel, eventHandler(), serverConfig);
            // 执行初始化
            this.channelInitializer.initChannel(nioChannel);
            this.idleDetector.addChannel(nioChannel);

            // 注册读事件
            socketChannel.register(acceptSelectorLoop().selector(), SelectionKey.OP_READ, nioChannel);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (nioChannel != null) {
            // 回调连接时的事件
            eventHandler().channelConnected(nioChannel);
        }
        return nioChannel;
    }

    @Override
    protected NioChannel doConnect(SocketAddress remoteAddress, NioSelectorLoop selectorLoop, Futures.ConnectFuture connectFuture) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void connect(SelectionKey key) {
        throw new UnsupportedOperationException();
    }

}